home *** CD-ROM | disk | FTP | other *** search
/ Shareware Super Platinum 8 / Shareware Super Platinum 8.iso / mac / WIN_VID / WINBM20.ZIP;1 / PCX.C < prev    next >
Encoding:
C/C++ Source or Header  |  1993-04-19  |  8.9 KB  |  390 lines

  1. /* $change:Modifications to fix errors in handling of some PCX files.$ */
  2. /*
  3. **    $id: ssvcid pcx.c 1.0 08/03/92 10:01 am$
  4. **        Support functions for reading in PCX files and creating a DIB.
  5. **
  6. **    (C) 1992-3 Larry Widing
  7. */
  8. #include    <windows.h>
  9. #include    <stdlib.h>
  10. #include    <mem.h>
  11. #include    "bitmaps.h"
  12. #include    "pcx.h"
  13.  
  14. #define    SEEK_SET    0
  15. #define    SEEK_END    2
  16.  
  17. /*
  18. **    PCX File Header Structure
  19. */
  20. typedef struct pcxhdr {
  21.     BYTE    manufacturer;        /*    10 == ZSoft */
  22.     BYTE    version;                /*    0 = Paintbrush 2.5
  23.                                     ** 2 = 2.8 with palette
  24.                                     ** 3 = 2.8 without palette
  25.                                     ** 4 = PC Paintbrush for Windows
  26.                                     ** 5 = Version 3.0+ and Publishers Paintbrush */
  27.     BYTE    encode;                /*    1 = PCX RLE */
  28.     BYTE    bitsPerPixel;        /* 1, 2, 4, or 8 */
  29.     short    minX;                    /* Window dimensions */
  30.     short    minY;
  31.     short    maxX;
  32.     short    maxY;
  33.     short    horzDpi;                /* Horizontal dots per inch */
  34.     short    vertDpi;                /* Vertical dots per inch */
  35.     RGBTRIPLE    pal1[16];    /* palette */
  36.     BYTE    junk;
  37.     BYTE    planes;                /* number of color planes */
  38.     short    bytesPerLine;        /* number of bytes per scanline */
  39.     short    paltype;                /* 1 = Color, 2 = GrayScale */
  40.     short    hScreenSize;        /* Horizontal Screen Size */
  41.     short    vScreenSize;        /* Vertical Screen Size */
  42.     BYTE    filler[54];
  43. } PCXHDR;
  44.  
  45. /*
  46. **    Note: Version 5 images may contain a 256 color palette at the end of the
  47. **    file.  Check for it by checking if the byte 769 bytes before the end of
  48. **    the file is 12.
  49. */
  50. typedef struct pcxpal256 {
  51.     BYTE            flag;            /* 12 if it exists */
  52.     RGBTRIPLE    pal2[256];    /* palette entries */
  53. } PCXPAL256;
  54.  
  55. /*
  56. **    Bit masks for planar decoding
  57. */
  58. static BYTE    LowMasks[4] = { 0x01, 0x02, 0x04, 0x08 };
  59. static BYTE HighMasks[4] = { 0x10, 0x20, 0x40, 0x80 };
  60.  
  61. /*
  62. **    Default 16 color VGA palette
  63. */
  64. static RGBTRIPLE DefaultPalette[16] = {
  65.     {   0,   0,   0 },
  66.     {   0,   0, 255 },
  67.     {   0, 255,   0 },
  68.     {   0, 255, 255 },
  69.     { 255,   0,   0 },
  70.     { 255,   0, 255 },
  71.     { 255, 255,   0 },
  72.     { 255, 255, 255 },
  73.     {  85,  85, 255 },
  74.     {  85,  85,  85 },
  75.     {   0, 170,   0 },
  76.     { 170,   0,   0 },
  77.     {  85, 255, 255 },
  78.     { 255,  85, 255 },
  79.     { 255, 255,  85 },
  80.     { 255, 255, 255 }
  81. };
  82.  
  83. /*
  84. ** static int                        -1 if an error occured, 0 otherwise
  85. ** PcxNextByte(
  86. **   BYTE *byte,                    pointer to resultant value
  87. **   int *count,                    pointer to repeat count, 1 if no repeat
  88. **   HANDLE fileHandle);        handle of file being read
  89. **
  90. **    Get the next byte from the PCX file, and determine if it is a repeat
  91. **    string or a literal byte.
  92. **
  93. ** Modification History:
  94. ** 07/31/92  LCW  Commented
  95. */
  96. static int
  97. PcxNextByte(BYTE *byte, int *count, int fileHandle)
  98. {
  99.     BYTE    value;
  100.  
  101.     *count = 1;
  102.     if (_lread(fileHandle, (LPSTR)&value, sizeof(value)) != sizeof(value))
  103.     {
  104.         return -1;
  105.     }
  106.  
  107.     /*
  108.     **    Check for a repeat count, indicated by the two high bits being set
  109.     */
  110.     if (0x00c0 == (0x00c0 & value))
  111.     {
  112.         *count = 0x3f & value;
  113.         if (_lread(fileHandle, (LPSTR)&value, sizeof(value)) != sizeof(value))
  114.         {
  115.             return -1;
  116.         }
  117.     }
  118.     *byte = value;
  119.  
  120.     return 0;
  121. }
  122.  
  123. /*
  124. ** HDIB                                            handle of resultant DIB, NULL on error
  125. ** ReadPcxFile(const char *filename);    name of file to load
  126. **
  127. **    Read a image in from a ZSoft PCX file, creating a Windows compatible
  128. **    DIB, and returning its handle to the caller.
  129. **
  130. ** Modification History:
  131. ** 07/31/92  LCW  Commented
  132. */
  133. HDIB
  134. ReadPcxFile(const char *filename)
  135. {
  136.     HDIB                        dib = (HDIB)NULL, dib2;
  137.     HFILE                        fileHandle;
  138.     LPBITMAPINFOHEADER    bmi;
  139.     RGBQUAD                     FAR *rgb;
  140.     RGBTRIPLE                *palPtr;
  141.     int                        i, j, colors, count, row, col, maxrow, plane;
  142.     BYTE                        chr, mask, bit, highbit;
  143.     DWORD                        dibSize;
  144.     PCXHDR                    pcxHeader;
  145.     PCXPAL256                pcxPal;
  146.     OFSTRUCT                    ofs;
  147.     long                        l, imageBytes, bytesPerScanLine, bytesPerImageLine;
  148.     unsigned char            HUGE *pixels;
  149.     unsigned char            HUGE *pPix;
  150.  
  151.     /*
  152.     **    Open the file
  153.     */
  154.     fileHandle = OpenFile(filename, (LPOFSTRUCT)&ofs, OF_READ);
  155.     if (fileHandle == -1)
  156.     {
  157.         return (HDIB)NULL;
  158.     }
  159.  
  160.     /*
  161.     **    Read in the header information, and verify it
  162.     */
  163.     _llseek(fileHandle, 0L, SEEK_SET);
  164.     if (sizeof(pcxHeader) != _lread(fileHandle, (LPSTR)&pcxHeader, sizeof(pcxHeader)))
  165.     {
  166.         _lclose(fileHandle);
  167.         return (HDIB)NULL;
  168.     }
  169.  
  170.     if (pcxHeader.manufacturer != 10)
  171.     {
  172.         _lclose(fileHandle);
  173.         return (HDIB)NULL;
  174.     }
  175.  
  176.     if (pcxHeader.bitsPerPixel * pcxHeader.planes == 1)
  177.     {
  178.         colors = 2;
  179.     }
  180.     else
  181.     {
  182.         colors = 16;
  183.     }
  184.  
  185.     /*
  186.     **    Set palPtr to point to the palette for this image
  187.     */
  188.     palPtr = pcxHeader.pal1;
  189.     if (pcxHeader.version == 5)
  190.     {
  191.         _llseek(fileHandle, -769L, SEEK_END);
  192.         if (sizeof(pcxPal) == _lread(fileHandle, (LPSTR)&pcxPal, sizeof(pcxPal))
  193.             && pcxPal.flag == 12)
  194.         {
  195.             colors = 256;
  196.             palPtr = pcxPal.pal2;
  197.         }
  198.     }
  199.  
  200.     /*
  201.     **    Create the bitmap header
  202.     */
  203.     dib = GlobalAlloc(GHND,
  204.         (LONG)sizeof(BITMAPINFOHEADER) + colors * sizeof(RGBQUAD));
  205.     if (dib == (HDIB)NULL)
  206.     {
  207.         _lclose(fileHandle);
  208.         return (HDIB)NULL;
  209.     }
  210.  
  211.     bmi = (LPBITMAPINFOHEADER)GlobalLock(dib);
  212.     bmi->biSize = sizeof(BITMAPINFOHEADER);
  213.     bmi->biWidth = 1 + pcxHeader.maxX - pcxHeader.minX;
  214.     bmi->biHeight = 1 + pcxHeader.maxY - pcxHeader.minY;
  215.     bmi->biPlanes = 1;
  216.     bmi->biBitCount = pcxHeader.bitsPerPixel * pcxHeader.planes;
  217.     if (bmi->biBitCount == 3)
  218.         bmi->biBitCount = 4;
  219.     bmi->biCompression = BI_RGB;
  220.    bmi->biSizeImage = ((DWORD)bmi->biBitCount * (DWORD)bmi->biWidth) / 8;
  221.     /*
  222.     **    NOTE: remember that each line of a DIB must align on a DWORD boundry
  223.     */
  224.     bmi->biSizeImage += (bmi->biSizeImage & 3) ? 4 - (bmi->biSizeImage & 3) : 0;
  225.    bytesPerImageLine = bmi->biSizeImage;
  226.     bmi->biSizeImage *= (DWORD)bmi->biHeight;
  227.     bmi->biXPelsPerMeter = 0;
  228.     bmi->biYPelsPerMeter = 0;
  229.     bmi->biClrUsed = colors;
  230.     bmi->biClrImportant = colors;
  231.  
  232.     /*
  233.     **    Fill in intensities for all palette entry colors.  Note the order
  234.     **    change between PCX and DIB.
  235.     */
  236.     rgb = (RGBQUAD FAR *)((LPSTR)bmi + (int)bmi->biSize);
  237.     for (i = 0 ; i < colors ; ++i)
  238.     {
  239.         rgb[i].rgbRed   = palPtr[i].rgbtBlue;
  240.         rgb[i].rgbGreen = palPtr[i].rgbtGreen;
  241.         rgb[i].rgbBlue  = palPtr[i].rgbtRed;
  242.         rgb[i].rgbReserved = 0;
  243.     }
  244.  
  245.     /*
  246.     **    Not all PCX files have a valid palette
  247.     */
  248.     if (pcxHeader.version == 2 || pcxHeader.version >= 4)
  249.     {
  250.         for (i = 0 ; i < colors ; ++i)
  251.         {
  252.             if (rgb[i].rgbRed != 0 || rgb[i].rgbGreen != 0 || rgb[i].rgbBlue != 0)
  253.             {
  254.                 break;
  255.             }
  256.         }
  257.     }
  258.     else
  259.     {
  260.         i = colors;
  261.     }
  262.  
  263.     if (i == colors)
  264.     {
  265.         if (colors <= 16)
  266.         {
  267.             /*
  268.             **    Use default 16 color palette
  269.             */
  270.             for (i = 0 ; i < colors ; ++i)
  271.             {
  272.                 rgb[i].rgbRed   = DefaultPalette[i].rgbtRed;
  273.                 rgb[i].rgbGreen = DefaultPalette[i].rgbtGreen;
  274.                 rgb[i].rgbBlue  = DefaultPalette[i].rgbtBlue;
  275.                 rgb[i].rgbReserved = 0;
  276.             }
  277.         }
  278.         else
  279.         {
  280.             /*
  281.             **    Use default Windows Palette
  282.             */
  283.             bmi->biClrUsed = bmi->biClrImportant = 0;
  284.         }
  285.     }
  286.  
  287.     dibSize = bmi->biSize + (DWORD)bmi->biClrUsed * sizeof(RGBQUAD) + bmi->biSizeImage;
  288.     dib2 = GlobalAlloc(GHND, dibSize);
  289.     if (dib2 == (HWND)NULL)
  290.     {
  291.         _lclose(fileHandle);
  292.         GlobalUnlock(dib);
  293.         GlobalFree(dib);
  294.         return (HDIB)NULL;
  295.     }
  296.     pixels = (unsigned char HUGE *)GlobalLock(dib2);
  297.     _fmemcpy(pixels, bmi, (size_t)(dibSize - bmi->biSizeImage));
  298.     GlobalUnlock(dib);
  299.     GlobalFree(dib);
  300.     dib = dib2;
  301.     bmi = (LPBITMAPINFOHEADER)pixels;
  302.     pixels += dibSize - bmi->biSizeImage;
  303.  
  304.     /*
  305.     **    Now to do the actual image reading
  306.     */
  307.     _llseek(fileHandle, (long)sizeof(pcxHeader), SEEK_SET);
  308.     bytesPerScanLine = (long)pcxHeader.bytesPerLine * (long)pcxHeader.planes;
  309.     imageBytes = bytesPerScanLine * bmi->biHeight;
  310.  
  311.     row = col = 0;
  312.     maxrow = (int)bmi->biHeight - 1;
  313.     for (l = 0 ; l < imageBytes ; )
  314.     {
  315.         if (-1 == PcxNextByte(&chr, &count, fileHandle))
  316.       {
  317.             goto read_exit;
  318.         }
  319.  
  320.         for (i = 0 ; i < count ; ++i)
  321.         {
  322.             /*
  323.             **    Locate the correct row and column
  324.             */
  325.             col = (int) ((l + i) % bytesPerScanLine);
  326.             row = (int) ((l + i) / bytesPerScanLine);
  327.  
  328.             if (row > maxrow || row < 0)
  329.             {
  330.                 goto read_exit;
  331.             }
  332.  
  333.             if (pcxHeader.planes == 3 || pcxHeader.planes == 4)
  334.             {
  335.                 plane = col / pcxHeader.bytesPerLine;
  336.                 if (plane < 0 || plane >= pcxHeader.planes)
  337.                 {
  338.                     goto read_exit;
  339.                 }
  340.                 col = col % pcxHeader.bytesPerLine;
  341.                 bit = LowMasks[plane];
  342.             highbit = HighMasks[plane];
  343.                 pPix = pixels + col * 4L + (long)(maxrow - row) * bytesPerImageLine;
  344.                 for (j = 0 ; j < 8 ; j += 2)
  345.                 {
  346.                     mask = 0x80 >> j;
  347.                     if (chr & mask)
  348.                {
  349.                         *pPix |= highbit;
  350.                     }
  351.  
  352.                     mask >>= 1;
  353.                     if (chr & mask)
  354.                     {
  355.                         *pPix |= bit;
  356.                     }
  357.                     ++pPix;
  358.                 }
  359.             }
  360.             else
  361.             {
  362.                 pPix = pixels + col + (maxrow - row) * bytesPerImageLine;
  363.                 *pPix = chr;
  364.             }
  365.         }
  366.         l += count;
  367.     }
  368.  
  369.    _lclose(fileHandle);
  370.    return dib;
  371.  
  372. read_exit:
  373.     _lclose(fileHandle);
  374.     GlobalUnlock(dib);
  375.     GlobalFree(dib);
  376.     dib = (HDIB)NULL;
  377.  
  378.     return dib;
  379. }
  380.  
  381. /*
  382. **    Modification History
  383. **    ====================
  384. **
  385. **    $lgb$
  386. ** 08/03/92     Larry Widing   Initial Version.
  387. **    $lge$
  388. */
  389.  
  390.